﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartRoute.Data;

namespace SmartRoute.Analytics
{
    /// <summary>
    /// The parameters provided to our simple cost function.
    /// </summary>
    [Serializable]
    public class CostFunctionParameters
    {
        private TimeSpan _busesAvailableTime;

        public TimeSpan BusesAvailableTime
        {
            get { return _busesAvailableTime; }
            set { _busesAvailableTime = value; }
        }

        private double _distanceCost;

        public double DistanceCost
        {
            get { return _distanceCost; }
            set { _distanceCost = value; }
        }
        private double _timeCost;

        public double TimeCost
        {
            get { return _timeCost; }
            set { _timeCost = value; }
        }
        private double _overloadCost;

        public double OverloadCost
        {
            get { return _overloadCost; }
            set { _overloadCost = value; }
        }

        private uint _passengerLimit;

        public uint PassengerLimit
        {
            get { return _passengerLimit; }
            set { _passengerLimit = value; }
        }

        private TimeSpan _ridingTimeLimit;

        public TimeSpan RidingTimeLimit
        {
            get { return _ridingTimeLimit; }
            set { _ridingTimeLimit = value; }
        }

        private double _overtimeCost;

        public double OvertimeCost
        {
            get { return _overtimeCost; }
            set { _overtimeCost = value; }
        }

        private double _baseBusCost;

        public double BaseBusCost
        {
            get { return _baseBusCost; }
            set { _baseBusCost = value; }
        }

        private TimeSpan[] _bellTimes;

        public IEnumerable<TimeSpan> BellTimes
        {
            get { return _bellTimes; }
            set { _bellTimes = value.ToArray(); }
        }

        private double _bellTimeMissCost;

        public double BellTimeMissCost
        {
            get { return _bellTimeMissCost; }
            set { _bellTimeMissCost = value; }
        }

        //Constructor for the cost function
        public CostFunctionParameters(double timeCost, double distanceCost, uint passengerLimit, TimeSpan riderTimeLimit,
            double overtimeCost, double overloadCost, double baseBusCost/*, TimeSpan earliestBusesMayLeave,*/ 
            /*IEnumerable<TimeSpan> bellTimes, double bellTimeMissCost*/)
        {
            _timeCost = timeCost;
            _distanceCost = distanceCost;
            _passengerLimit = passengerLimit;
            _ridingTimeLimit = riderTimeLimit;
            _overtimeCost = overtimeCost;
            _overloadCost = overloadCost;
            _baseBusCost = baseBusCost;
            //_bellTimes = bellTimes.ToArray();
        }

        protected CostFunctionParameters() { }
    }

    public static class CostFunctions
    {
        //public static Analyzer<CostFunctionParameters> MakeSimpleCostFunction(double distanceCost, double timeCost,
        //    TimeSpan riderTimeLimit, int busCapacity, double overloadCost, double overtimeCost)
        //{
        //    return new Analyzer<CostFunctionParameters>(SimpleCostFunction, new CostFunctionParameters(timeCost,distanceCost,busCapacity,
        //                                                                          riderTimeLimit,overtimeCost,overloadCost));
        //}

        public static readonly Func<CostFunctionParameters, IEnumerable<Bus>, double> SimpleCostFunction =
            new Func<CostFunctionParameters, IEnumerable<Bus>, double>((x, ys) => ys.Select(y => CostFunctions.SimpleCostMethod(x, y)).Sum());
        

        private static double SimpleCostMethod(CostFunctionParameters parameters, Bus bus)
        {
            double accum = 0;
            if (bus.Used)
            {
                if (bus.TimeStudentSpentOnBus > parameters.RidingTimeLimit)
                    accum += (bus.TimeStudentSpentOnBus - parameters.RidingTimeLimit).Minutes * parameters.OvertimeCost;
                if (bus.Passengers > parameters.PassengerLimit)
                    accum += (bus.Passengers - parameters.PassengerLimit) * parameters.OverloadCost;
                accum += bus.Duration.Minutes * parameters.TimeCost;
                accum += bus.Distance * parameters.DistanceCost;
                accum += parameters.BaseBusCost;
            }
            return accum;
        }
    }
}
